package common.project.epic.core;

//########
// TODO CHECK STANFORD CODE 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelUuid;
//########

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Date;
import java.util.EmptyStackException;
import java.util.Random;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.provider.MediaStore.*;


import android.util.Log;

import common.project.epic.db.CurrentUser;
import common.project.epic.db.EpicContentManipulation;
import common.project.epic.db.EpicDBAdapter;
import common.project.epic.db.EpicDBRTAdapter;
import common.project.epic.db.EpicDevice;
import common.project.epic.db.EpicMsgIdPriority;
import common.project.epic.db.EpicNote;

public class IOEpicService extends Service {	
	private InputStream inputstream = null;
	private OutputStream outputstream = null;
	private static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
	boolean mAllowRebind; // indicates whether onRebind should be used
	
	//Debug purpose
	private static final boolean D = true;
	private static final String TAG = "IOEpic";
	//UUID used by BT SDP
	private static final String EPIC_STRING = "cdc9e792526b13c20304099b001ace6f"; 
	private static final byte[] EPIC_BYTE = EPIC_STRING.getBytes();
	private static final UUID EPIC_UUID = UUID.nameUUIDFromBytes(EPIC_BYTE);
	private static final String NAME_INSECURE = "EpicIO";

	private Context mContext; 
	private BluetoothAdapter mBTAdapter;
	
	private int mState;
	
	public static final int STATE_NONE = 0; 
	public static final int STATE_LISTENING = 1; 
	public static final int STATE_DISCOVERING = 2; 
	public static final int STATE_COMMUNICATION = 3;
	public static final int STATE_POST_DISCOVERING = 4;
	int mStartMode = START_STICKY; // indicates how to behave if the service is killed
	
	public static final int MAX_NUMBER_OF_DESCOVERED_DEVICES = 10;
	private EpicDevice[] discoveredDevices;
	private EpicDevice epicDevice;
	private int devicesCounter;
	
	private Timer listeningTimer;
	private Timer discoveryTimer;
	private Timer communicationTimer;
	private static final int LISTENING_PERIOD = 50000; // [ms]
	private static final int DISCOVERY_PERIOD = 10000; // [ms]
	private static final int STOP_COMMUNICATION_PERIOD = 120000; // [ms]
	
	private int TEST_PERIOD = 100; // [ms]
	
	private ConnectThread mConnectThread;
	private ConnectedThread mConnectedThread;
	private AcceptThread mAcceptThread;
	
	//Location Service variables
	boolean mLocBound = false;
	private ILocationEpicService mILocationEpicService = null;
	
	//data adapter
//	Blacklisted,Discovered History Devices DataAdapter
//	private EpicDBRTAdapter rtDataAdapter;
	//Content DataAdapter
	private EpicDBAdapter dbHelper;
	
	
	//Comm protocol constants
	private static final int INFO_PACKET_LENGTH = 19;
	private static final int META_PROP_PACKET_LENGTH = 51;
	private static final int META_ECHO_PACKET_LENGTH = 3;
	private static final int CONTENT_PACKET_FIXED_LENGTH = 97;
	
	private boolean deferred_sending = false;
	
	//#########################################################
	@Override
	public IBinder onBind(Intent intent) {
		if (IOEpicService.class.getName().equals(intent.getAction())) {
            return mSecondaryBinder;
        }
		return null;
	}
	
	//#########################################################
	@Override
	public void onCreate() {
		// service created
		// TODO be sure the device is DISCOVERABLE 
//		android.os.Debug.waitForDebugger();
		
		mContext = this.getApplicationContext();
		mBTAdapter = BluetoothAdapter.getDefaultAdapter();
		
//		if(mBTAdapter.getState() == BluetoothAdapter.STATE_OFF || 
//				mBTAdapter.getState() == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
//		if(mBTAdapter.getState() == BluetoothAdapter.STATE_OFF) {
//			stopSelf();
//		}
		
		dbHelper = new EpicDBAdapter(mContext);
		// mState = STATE_NONE
		setState(STATE_NONE);
		
		devicesCounter = 0;
		discoveredDevices = new EpicDevice[MAX_NUMBER_OF_DESCOVERED_DEVICES];
		
		listeningTimer = new Timer();
		discoveryTimer = new Timer();
		communicationTimer = new Timer();
		
		IntentFilter findDeviceIntentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    	// this BroadcastReceiver is used after calling startDiscovery() method
        registerReceiver(mReceiver, findDeviceIntentFilter);
        
        registerReceiver(ScanModeChangedReceiver, new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED));
        
        Log.d("IOEpicService", "onCreate()");
        
        listeningTimer.schedule(new DiscoveryTask(), TEST_PERIOD);
		mAcceptThread = new AcceptThread();
		mAcceptThread.run();
	}	
	
	
	//#########################################################	
	// Create a BroadcastReceiver for Bluetooth ACTION_FOUND
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            // When discovery finds a device and I'm in STATE_DISCOVERING
            if (BluetoothDevice.ACTION_FOUND.equals(action) && mState==STATE_DISCOVERING) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                Bundle intentExtra = intent.getExtras();                
                if(epicDevice != null) {
                	epicDevice = null;
                }
                epicDevice = new EpicDevice();
                
                short rssi = intentExtra.getShort("android.bluetooth.device.extra.RSSI");
                
                epicDevice.setMac(device.getAddress());
                epicDevice.setName(device.getName());
                epicDevice.setRssi(rssi);
                epicDevice.setDiscovered_at();
                
                devicesCounter++;
                
                if(devicesCounter <= MAX_NUMBER_OF_DESCOVERED_DEVICES){
                	discoveredDevices[devicesCounter-1] = epicDevice;
                	Log.d("IOEpicService, BroadcastReceiver", "# of found BluetoothDevice = " + devicesCounter);
                }
                else {
                	Log.d("IOEpicService, BroadcastReceiver", "devicesCounter > MAX_NUMBER_OF_DESCOVERED_DEVICES");
                	
                	discoveryTimer.cancel();                	
                	discoveryTimer = null;
                	discoveryTimer = new Timer();
                	
                	devicesCounter--;
                	EpicDevice selectedDevice = getSelectedNeighborDevice();
                	
                	if(mConnectThread != null) {
                		mConnectThread.cancel();
                		mConnectThread = null;
                	}
                	mConnectThread = new ConnectThread(selectedDevice);
                	Log.d("IOEpicService, BroadcastReceiver", "new ConnectThread(selectedDevice);");
                	
                	Log.d("IOEpicService, BroadcastReceiver", "mConnectThread.run();");
                	mConnectThread.run();
                }
            }
        }
    };
	//#########################################################
	public void startListeningTimer() {
		Log.d("IOEpicService", "startListeningTimer()");
		if(mConnectThread != null){
			//mConnectThread.cancel();
			//mConnectThread = null;
		}
		if(mConnectedThread != null){
			mConnectedThread.cancel();
			mConnectedThread = null;
		}
		// start listeningTimer
		if(listeningTimer != null) {
//			Log.d("IOEpicService, startListeningTimer()", "listeningTimer != null => set to null");
			listeningTimer = null;
		}
//		Log.d("IOEpicService, startListeningTimer()", "listeningTimer = new Timer();");
		listeningTimer = new Timer();
		if(communicationTimer != null) {
			communicationTimer.cancel();
			communicationTimer = null;
		}
		communicationTimer = new Timer();
		int cyclePeriod = LISTENING_PERIOD + DISCOVERY_PERIOD;
		int timeOffset = (int)(Math.random()*cyclePeriod);
		listeningTimer.schedule(new DiscoveryTask(), LISTENING_PERIOD+timeOffset);
		TEST_PERIOD = LISTENING_PERIOD+timeOffset;
		Log.d("IOEpicService, startListeningTimer()", "listeningTimer.schedule(new DiscoveryTask()," + TEST_PERIOD + ");");
		if(mAcceptThread != null) {
			Log.d("IOEpicService, startListeningTimer()", "mAcceptThread != null => set to null");
			mAcceptThread.cancel();
			mAcceptThread = null;
		}
//		Log.d("IOEpicService, startListeningTimer()", "mAcceptThread = new AcceptThread();");
		mAcceptThread = new AcceptThread();
//		Log.d("IOEpicService, startListeningTimer()", "mAcceptThread.run();");
		mAcceptThread.run();
	}
	
	//#########################################################
	@Override
	public void onDestroy() {
		// service stopped
//		rtDataAdapter.close();
		if(listeningTimer != null) {
			listeningTimer.cancel();
			listeningTimer = null;
		}
		if(discoveryTimer != null) {
			discoveryTimer.cancel();
			discoveryTimer = null;
		}
		if(communicationTimer != null) {
			communicationTimer.cancel();
			communicationTimer = null;
		}
		if(mAcceptThread != null){
			mAcceptThread.cancel();
			mAcceptThread = null;
		}
		if(mConnectThread != null){
			mConnectThread.cancel();
			mConnectThread = null;
		}
		if(mConnectedThread != null){
			mConnectedThread.cancel();
			mConnectedThread = null;
		}
	}
	
	@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
		Intent intentloc = new Intent(this, LocationEpicService.class);
        bindService(intentloc, mLocServiceConnection, Context.BIND_AUTO_CREATE);
    	return mStartMode;
    }
	
	//##################################################################################
	private final BroadcastReceiver ScanModeChangedReceiver = new BroadcastReceiver(){
    	@Override
    	public void onReceive(Context context, Intent intent) {
    		String action = intent.getAction();
    		if(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
    			int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.ERROR);
    			switch(mode){
    			case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
    				Log.d("bluetooth", "connectable discoverable");
    				if(mStopCommunication != null) {
    					mStopCommunication = null;
    				}
                	if(mAcceptThread==null) {
                		Timer timerTmp = new Timer();
                		timerTmp.schedule(new TimerTask() {
                			public void run() {
    		                	startListeningTimer();
        	                }
                		}, 10000);
                	}
                	else {
                		Log.d("bluetooth broadcast receiver", "mAcceptThread != null");
                	}
    				break;
    			case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
    				Log.d("bluetooth", "connectable");
    				if(mStopCommunication==null) {
    					mStopCommunication = new StopCommunication();
        				mStopCommunication.run();
    				}
    				break;
    			case BluetoothAdapter.SCAN_MODE_NONE:
    				Log.d("bluetooth", "mode none");
    				if(mStopCommunication==null) {
    					mStopCommunication = new StopCommunication();
    					mStopCommunication.run();
    				}
    				break;
    			default:
    				Log.d("bluetooth (case default)", action);
    				if(mStopCommunication==null) {
	    				mStopCommunication = new StopCommunication();
	    				mStopCommunication.run();
    				}
					break;
    			}
            }
    	}
    };
    
    private StopCommunication mStopCommunication;
    private class StopCommunication extends Thread {
	    public StopCommunication() {}
	    public void run() {
	    	setState(STATE_NONE);
	    	// do nothing since bluetooth is not active
	    	if(listeningTimer != null) {
				listeningTimer.cancel();
				listeningTimer = null;
				listeningTimer = new Timer();
			}
			if(discoveryTimer != null) {
				discoveryTimer.cancel();
				discoveryTimer = null;
				discoveryTimer = new Timer();
			}
			if(communicationTimer != null) {
				communicationTimer.cancel();
				communicationTimer = null;
				communicationTimer = new Timer();
			}
	    	if(mAcceptThread != null) {
				mAcceptThread.cancel();
				mAcceptThread = null;
			}
			if(mConnectThread != null) {
				mConnectThread.cancel();
				mConnectThread = null;
			}
			if(mConnectedThread != null) {
				mConnectedThread.cancel();
				mConnectedThread = null;
			}
	    }
	}
    //##################################################################################
	
	//#########################################################
	// ACCEPT THREAD
	//#########################################################
	private class AcceptThread extends Thread {
	    private final BluetoothServerSocket mmServerSocket;
	 
	    public AcceptThread() {
	        // Use a temporary object that is later assigned to mmServerSocket, because mmServerSocket is final
	        BluetoothServerSocket tmp = null;
	        Log.d("AcceptThread", "Try to open BluetoothServerSocket");
	        try {
	        	
	        	if(Build.VERSION.SDK_INT<=10) {
	        		//########
		        	// TODO CHECK STANFORD CODE 
		            tmp = InsecureBluetooth.listenUsingRfcommWithServiceRecord(mBTAdapter, NAME_INSECURE, EPIC_UUID, false);
		            //########
	        	}
	        	else {
	        		tmp = mBTAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, EPIC_UUID);
	        	}
	            
	            Log.d("AcceptThread", "Open BluetoothServerSocket succeeded");
	        } 
	        catch (IOException e) {
	        	Log.d("AcceptThread", "Open BluetoothServerSocket failed" + e);
	        }
	        mmServerSocket = tmp;	       
	    }
	 
	    public void run() {
	    	Log.d("AcceptThread, run()", "Set mState = STATE_LISTENING");
	    	setState(STATE_LISTENING);
	    	
//	    	if(mConnectThread != null){
//				//mConnectThread.cancel();
//				//mConnectThread = null;
//			}
			if(mConnectedThread != null){
				mConnectedThread.cancel();
				mConnectedThread = null;
			}
	    	
	        BluetoothSocket socket = null;
	        // Keep listening until exception occurs or a socket is returned
	        while (true) {
	        	
	        	Log.d("AcceptThread, run()","mmServerSocket.accept();");
		        try {
		        	if(mmServerSocket==null) {
		        		Log.d("AcceptThread, run()","mmServerSocket == null");
		        	}
		        	else {
		        		socket = mmServerSocket.accept(TEST_PERIOD);
			            Log.d("AcceptThread, run()","Connection accepted: valid socket");
		        	}
		        } 
		        catch (IOException e) {
		        	Log.d("AcceptThread, run()","IOException: no incoming connection");
		        	// TODO check if it is necessary to close the server socket in this case
		        	try {
		        		mmServerSocket.close();
		        	} 
		        	catch(IOException e1) {
		        		e1.printStackTrace();
		        	}
		            break;
		        }
		        
		        // If a connection was accepted
		        if (socket != null) {
		        	Log.d("AcceptThread, run()","socket not null");
		        	synchronized (IOEpicService.this) {
//		            	// TODO since I have an accepted socket should I close here the server socket??? 
			           	try {
							mmServerSocket.close();
							Log.d("AcceptThread, run()","socket != null");
						} catch (IOException e) {
							Log.e(TAG, "Not able to close the server connection", e);
							break;
						}
			           	
			            if(listeningTimer != null) {
			            	listeningTimer.cancel();
			            	listeningTimer = null;
			            }
			            
//			        	connected(socket, socket.getRemoteDevice());
			            
			            Log.d("AcceptThread, run()","new ConnectedThread(socket);");
			           	mConnectedThread = new ConnectedThread(socket);
			           	
			           	Log.d("AcceptThread, run()","mConnectedThread.run();");
			            mConnectedThread.run();
		                break;		            
		            }
		        }
		        else {
		        	Log.w("AcceptThread, run()","socket == null. Check the correctness of the following code: " +
		        			"startListeningTimer(); break;");
		        	startListeningTimer();
		        	break;
		        }
		    }
	    }
	 
	    /** Will cancel the listening socket, and cause the thread to finish */
	    public void cancel() {
	        try {
	        	Log.w("AcceptThread, run()","mAcceptThread.cancel()=>mmServerSocket.close()");
	            mmServerSocket.close();
	        } catch (IOException e) { 
	        	Log.e(TAG, "mAcceptThread.close()", e);
	        }
	    }
	}
	
	
	
	//#########################################################
    private class ConnectThread extends Thread {
    	private BluetoothSocket mmSocket;
        private BluetoothDevice mmDevice;
        
        public ConnectThread(EpicDevice device) {
        	BluetoothSocket tmp = null;
            mmDevice = mBTAdapter.getRemoteDevice(device.getMac());
            
            Log.d("ConnectThread", "Try connection with bluetooth device: " + device.getMac());     
            // Get a BluetoothSocket for a connection with the given EpicDevice
            try {
            	
            	if(Build.VERSION.SDK_INT<=10) {
	        		//########
		        	// TODO CHECK STANFORD CODE 
		            tmp = InsecureBluetooth.createRfcommSocketToServiceRecord(mmDevice, EPIC_UUID, false);
		            //########
	        	}
	        	else {
	        		tmp = mmDevice.createInsecureRfcommSocketToServiceRecord(EPIC_UUID);
	        	}
                
                Log.d("ConnectThread","Socket creation succeeded!");
            } 
            catch (IOException e) {
            	Log.d("ConnectThread","Socket creation failed!");
            	Log.e(TAG, "Socket Type: INSECURE create() failed", e);
            }
            mmSocket = tmp;
        }

        public void run() {
        	mBTAdapter.cancelDiscovery();
        	if(mAcceptThread != null){
				mAcceptThread.cancel();
				mAcceptThread = null;
			}
			if(mConnectedThread != null){
				mConnectedThread.cancel();
				mConnectedThread = null;
			}
        	
            Log.i(TAG, "BEGIN mConnectThread SocketType: INSECURE");

            Log.d("ConnectThread, run()","Try socket connection");
            try {
                // Connect the device through the socket. This will block
                // until it succeeds or throws an exception
                mmSocket.connect();
                Log.d("ConnectThread, run()","Socket connection succeeded");
                
//              connected(mmSocket, mmSocket.getRemoteDevice());
            	mConnectedThread = new ConnectedThread(mmSocket);
                mConnectedThread.run();
            } catch (IOException connectException) {
                // Unable to connect; close the socket and get out
            	Log.d("ConnectThread, run()","Socket connection failed: no EPIC user");
//            	TEST_PERIOD = LISTENING_PERIOD;
            	cleanSelectedDevice();
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect INSECURE socket failed", e);
            }
        }
    }
	
    //#########################################################
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;
        
        private byte[] infobufferTX = new byte[INFO_PACKET_LENGTH];
        private byte[] infobufferRX = new byte[INFO_PACKET_LENGTH];
        
        private byte[] meta_proposal_bufferTX = new byte[META_PROP_PACKET_LENGTH];
        private byte[] meta_proposal_bufferRX = new byte[META_PROP_PACKET_LENGTH];
        
        private byte[] meta_echo_bufferTX = new byte[META_ECHO_PACKET_LENGTH];
        private byte[] meta_echo_bufferRX = new byte[META_ECHO_PACKET_LENGTH];
        
        private byte[] content_bufferTX;
        private byte[] content_bufferRX;
        
        private EpicMsgIdPriority[] tmpEMId = new EpicMsgIdPriority[8];
        
        private int bytes;
        private Stack contentStack = null;
        private boolean hasMore = true;
        
        public ConnectedThread(BluetoothSocket socket) {
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // Get the input and output streams, using temp objects because member streams are final
            try {
                tmpIn = socket.getInputStream();
                Log.d("ConnectedThread ","socket.getInputStream() succeeded");
            } catch (IOException e) { 
            	Log.d("ConnectedThread ","socket.getInputStream() failed");
            }
            try {
				tmpOut = socket.getOutputStream();
				Log.d("ConnectedThread ","socket.getOutputStream() succeeded");
			} catch (IOException e) {
				Log.d("ConnectedThread ","socket.getOutputStream() failed");
			}
     
            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
        	
			if(mState==STATE_LISTENING) {
        		Log.d("ConnectedThread","run(): start communicationSlave()");
        		setState(STATE_COMMUNICATION);
        		
        		communicationSlave();
        	}
        	else if(mState==STATE_POST_DISCOVERING || mState==STATE_DISCOVERING) {
        		Log.d("ConnectedThread","run(): start communicationMaster()");
        		setState(STATE_COMMUNICATION);
        		
        		communicationMaster();
        	}
        	else {
        		Log.d("ConnectedThread","run(): ATTENTION: mState not valid!!!");
        	}
        }

		/* Call this from the main Activity to send data to the remote device */
        public void write(byte[] bytes) {
            try {
                mmOutStream.write(bytes);
            } catch (IOException e) { 
            	Log.e(TAG, "write on mmOutStream failed. Pck not sent", e);
            }
            try {
            	mmOutStream.flush();
            } catch (IOException e) { 
            	Log.e(TAG, "mmOutStream.flush() failed", e);
            }
            return;
        }
        
        
        public int read(byte[] bytes, int offset) {
        	int numberOfByteRead = 0;
            try {
            	int availableByte = mmInStream.available();
            	if(availableByte>0) {
            		int byteToRead = Math.min(availableByte, bytes.length-offset);
            		numberOfByteRead = mmInStream.read(bytes, offset, byteToRead);
            	}
            } catch (IOException e) { 
            	Log.d("ConnectedThread", "Connection lost during pck reception");
            	return -2;
            }
            return numberOfByteRead;
        }
     
        /* Call this from the main Activity to shutdown the connection */
        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) { 
            	Log.e(TAG, "close() of connected, socket failed", e);
            }
        }
        
        //##############################################################################################################################
        //##############################################################################################################################
        public boolean contentPacketRx(String tag, boolean checkVandT, boolean exceptionNotCatched, int accepted,
        		String yourUsername, long deliveryTime, double deliveryLat, double deliveryLon, double deliveryAlt) {
    		// TODO Since we rx a content pck at a time, be sure that the receiver gives us the time
    		// to read the buffer and perform the require operation before he sends the next content pck
    		
    		for(int j=0; j<accepted; j++) {
    			
    			//############################
    			// content packet fixed part #
    			//############################
    			byte[] content_bufferRX = new byte[CONTENT_PACKET_FIXED_LENGTH];
    			int nOfByte = 0;
    			int nob = 0;
    			int byteOffset = 0;
    			while(nOfByte < CONTENT_PACKET_FIXED_LENGTH) {
    				nob = read(content_bufferRX, byteOffset);
    				if(nob==-2) {
    					Log.d(tag, "Connection lost during content pck (fixed part) reception");
    					exceptionNotCatched = false;
    					startListeningTimer();
    					return exceptionNotCatched;
    				}
    				else if(nob==-1) {
    					Log.d(tag, "End of inputStram reached!!!");
    					break;
    				}
    				else {
    					nOfByte = nOfByte + nob;
    					byteOffset = nOfByte;
    				}
    			}
    			if(!exceptionNotCatched) {
    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
    				Log.d(tag, "An exception occurred => break;");
    				break;
    			}
    			if(checkVandT) {
    				int typerx = (content_bufferRX[0] & 0xF0)>>4;
            		int versionrx = (content_bufferRX[0] & 0x0F);
            		if(typerx != EpicVersionSettings.contentType) {
            			//TODO Manage incorrect type packet reception
            			Log.d(tag, "Wrong pck type: expected = " + 
            			EpicVersionSettings.contentType + " received = " + typerx);
            		}
            		else
            		{
            			Log.d(tag, "Content fixed part read.");
            		}
    			}
    			
    			// retrieve fixed fields of received content packet
    			Object[] contentFixed = getContentFixedPart(content_bufferRX);
                String msgId = (String)contentFixed[0];
                long msgExpTime = (Long) contentFixed[1];
                double msgLat = (Double) contentFixed[2];
                double msgLon = (Double) contentFixed[3];
                double msgAlt = (Double) contentFixed[4];
                int msgGeoSpan = (Integer) contentFixed[5];
                String msgCategories = (String)contentFixed[6];
                String msgCreatorId = (String)contentFixed[7];
                String msgCreatorNick = (String)contentFixed[8];
                int hopNumber = (Integer) contentFixed[9];
                int approximateMsgSize = (Integer) contentFixed[10];
                double rxRate = (Double) contentFixed[11];
                long crcCheck = (Long) contentFixed[12];
                int attachNumber = (Integer) contentFixed[13];
                int titleLength = (Integer) contentFixed[14];
                int contentLength = (Integer) contentFixed[15];
                
                Log.d(tag, "Content packet received: fixed part read");
                
                // TODO compute CRC
        		// msgId, msgExpTime, msgLat, msgLon, msgAlt, msgGeoSpan, msgCat, creatorUserName, creatorNickName,
        		// msgTitle, msgContent,
        		// attachments' byte stream
        		Checksum checksum = new CRC32();
                checksum.update(content_bufferRX, 1, 6); // msgId
                checksum.update(content_bufferRX, 7, 4); // msgExpTime
                checksum.update(content_bufferRX, 11, 8); // msgLat
                checksum.update(content_bufferRX, 19, 8); // msgLon
                checksum.update(content_bufferRX, 27, 8); // msgAlt
                checksum.update(content_bufferRX, 35, 2); // msgGeoSpan
                checksum.update(content_bufferRX, 37, 2); // msgCat
                checksum.update(content_bufferRX, 39, 16); // creatorUserName
                checksum.update(content_bufferRX, 55, 16); // creatorNickName
            	
    			//###############################
    			// content packet variable part #
    			//###############################
                //#################
                // read msg title #
                //#################
                byte[] title_bufferRX = new byte[titleLength];
                String msgTitle = "";
                nOfByte = 0;
    			nob = 0;
    			byteOffset = 0;
                while(nOfByte < titleLength) {
    				nob = read(title_bufferRX, byteOffset);
    				if(nob==-2) {
    					Log.d(tag, "Connection lost during content pck (title) reception");
    					exceptionNotCatched = false;
    					startListeningTimer();
    					return exceptionNotCatched;
    				}
    				else if(nob==-1) {
    					Log.d(tag, "End of inputStram reached!!!");
    					break;
    				}
    				else {
    					nOfByte = nOfByte + nob;
    					byteOffset = nOfByte;
    				}
                }
                if(!exceptionNotCatched) {
    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
    				Log.d(tag, "An exception occurred => break;");
    				break;
    			}
                msgTitle = new String(title_bufferRX);
                Log.d(tag, "Content packet received: title read");
                
//                checksum.update(title_bufferRX, 0, title_bufferRX.length);
                
                //###################
                // read msg content #
                //###################
                byte[] text_bufferRX = new byte[contentLength];
                String msgContent = "";
                nOfByte = 0;
    			nob = 0;
    			byteOffset = 0;
                while(nOfByte < contentLength) {
    				nob = read(text_bufferRX, byteOffset);
    				if(nob==-2) {
    					Log.d(tag, "Connection lost during content pck (content) reception");
    					exceptionNotCatched = false;
    					startListeningTimer();
    					return exceptionNotCatched;
    				}
    				else if(nob==-1) {
    					Log.d(tag, "End of inputStram reached!!!");
    					break;
    				}
    				else {
    					nOfByte = nOfByte + nob;
    					byteOffset = nOfByte;
    				}
                }
                if(!exceptionNotCatched) {
    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
    				Log.d(tag, "An exception occurred => break;");
    				break;
    			}
                msgContent = new String(text_bufferRX);
                Log.d(tag, "Content packet received: content read");

//                checksum.update(text_bufferRX, 0, text_bufferRX.length);
                
    			//###################
    			// read attachments #
    			//###################
    			// TODO retrieve type and byte stream of attachments and set the right uri in EpicDB after storage   
    			String attach_extension_array;
    			String attach_path_array = null;
    			Object[] attach_content_array;
    			String[] attach_filename_array;
    			
    			if(attachNumber>0) {
    				Log.d(tag, "Start read " + attachNumber + " attachments");
    				
    				attach_extension_array = "";
    				attach_content_array = new Object[attachNumber];
    				attach_filename_array = new String[attachNumber];
    			
    				// if(attachNumber > 0) {read attachments} 
    				for(int jj=0; jj<attachNumber; jj++) {
    					//#################################################################
    					// read filename length (1 byte) and filename of jj-th attachment #
    					//#################################################################
    					// filename length
    					byte[] attachFilenameLength = new byte[1];
    					nOfByte = 0;
    	    			nob = 0;
    	    			byteOffset = 0;
    					while(nOfByte < attachFilenameLength.length) {
    	    				nob = read(attachFilenameLength, byteOffset);
    	    				if(nob==-2) {
    	    					Log.d(tag, 
    	    							"Connection lost during content pck (attachment file name length) reception");
    	    					exceptionNotCatched = false;
    	    					startListeningTimer();
    	    					return exceptionNotCatched;    	    					
    	    				}
    	    				else if(nob==-1) {
    	    					Log.d(tag, "End of inputStram reached!!!");
    	    					break;
    	    				}
    	    				else {
    	    					nOfByte = nOfByte + nob;
    	    					byteOffset = nOfByte;
    	    				}
                        }
    					if(!exceptionNotCatched) {
    	    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
    	    				Log.d(tag, "An exception occurred => break;");
    	    				break;
    	    			}
    					// filename
    					byte[] attachFilename = new byte[(attachFilenameLength[0]&0xff)];
    					nOfByte = 0;
    	    			nob = 0;
    	    			byteOffset = 0;
    					while(nOfByte < attachFilename.length) {
    	    				nob = read(attachFilename, byteOffset);
    	    				if(nob==-2) {
    	    					Log.d(tag, 
    	    							"Connection lost during content pck (attachment file name) reception");
    	    					exceptionNotCatched = false;
    	    					startListeningTimer();
    	    					return exceptionNotCatched;
    	    				}
    	    				else if(nob==-1) {
    	    					Log.d(tag, "End of inputStram reached!!!");
    	    					break;
    	    				}
    	    				else {
    	    					nOfByte = nOfByte + nob;
    	    					byteOffset = nOfByte;
    	    				}
                        }
    					if(!exceptionNotCatched) {
    	    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
    	    				Log.d(tag, "An exception occurred => break;");
    	    				break;
    	    			}
    					attach_filename_array[jj] = new String(attachFilename);
    					//#############################################################
    					// read type (1 byte) and length (3 byte) of jj-th attachment #
    					//#############################################################
    					byte[] attach_fileExtension_fileLength = new byte[4];
    					nOfByte = 0;
    	    			nob = 0;
    	    			byteOffset = 0;
                        while(nOfByte < attach_fileExtension_fileLength.length) {
    	    				nob = read(attach_fileExtension_fileLength, byteOffset);
    	    				if(nob==-2) {
    	    					Log.d(tag, 
    	    							"Connection lost during content pck (attachment's extension and length) reception");
    	    					exceptionNotCatched = false;
    	    					startListeningTimer();
    	    					return exceptionNotCatched;
    	    				}
    	    				else if(nob==-1) {
    	    					Log.d(tag, "End of inputStram reached!!!");
    	    					break;
    	    				}
    	    				else {
    	    					nOfByte = nOfByte + nob;
    	    					byteOffset = nOfByte;
    	    				}
                        }
    					if(!exceptionNotCatched) {
    	    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
    	    				Log.d(tag, "An exception occurred => break;");
    	    				break;
    	    			}
    					if(jj>0) {
    						attach_extension_array = attach_extension_array + "," + 
    								dbHelper.resolveAttachmentType((int)(attach_fileExtension_fileLength[0] & 0xFF));
    					}
    					else {
    						attach_extension_array = 
    								dbHelper.resolveAttachmentType((int)(attach_fileExtension_fileLength[0] & 0xFF));
    					}
    					Log.d(tag, "Attachment type = " + attach_extension_array);
    					int attachment_length = (attach_fileExtension_fileLength[1] & 0xFF)*65536 + 
    							(attach_fileExtension_fileLength[2] & 0xFF)*256 + 
    							(attach_fileExtension_fileLength[3] & 0xFF);
    					Log.d(tag, "Attachment length = " + attachment_length);
    					
    					// read the jj-th attachment
    					byte[] attachment_buffer = new byte[attachment_length];
    					nOfByte = 0;
    	    			nob = 0;
    	    			byteOffset = 0;
                        while(nOfByte < attachment_length) {
    	    				nob = read(attachment_buffer, byteOffset);
    	    				if(nob==-2) {
    	    					Log.d(tag, 
    	    							"Connection lost during content pck (attachment number " + jj + ") reception");
    	    					exceptionNotCatched = false;
    	    					startListeningTimer();
    	    					return exceptionNotCatched;
    	    				}
    	    				else if(nob==-1) {
    	    					Log.d(tag, "End of inputStram reached!!!");
    	    					break;
    	    				}
    	    				else {
    	    					nOfByte = nOfByte + nob;
    	    					byteOffset = nOfByte;
    	    				}
                        }
    					if(!exceptionNotCatched) {
    	    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
    	    				Log.d(tag, "An exception occurred => break;");
    	    				break;
    	    			}
    					attach_content_array[jj] = attachment_buffer;
    					Log.d(tag, "Attachment retrieved");
    				}
    				if(!exceptionNotCatched) {
        				// if an exception occurs during the reading we break from the main while(exception_not_catched)
        				Log.d(tag, "An exception occurred => break;");
        				break;
        			}
    			} // END if(attachNumber>0)
    			else { 
    				// No attachments
    				attach_extension_array = null;
    				attach_path_array = null;
    				attach_content_array = null;
    				attach_filename_array = null;
    			}

    			CurrentUser.readCurrentUserSettings(mContext);
    			
    			dbHelper.open();
    			
    			if(attachNumber>0) {
    				attach_path_array = "";
    				
    				String[] type_array = attach_extension_array.split(",");
    				// store the attachments in the appropriate content provider
    				
    				int ii = 0;
    				for(Object element: attach_content_array) {
    					byte[] element_tmp = (byte[]) element;
    					checksum.update(element_tmp, 0, element_tmp.length);
    					String element_ext = type_array[ii];
    					String file_path = dbHelper.addAttachment(msgId, attach_filename_array[ii], element_ext, element_tmp);
    					if(ii>0) {
    						attach_path_array = attach_path_array + "," + file_path;
    					}
    					else {
    						attach_path_array = file_path;
    					}
    					ii++;
    				}
    				
    				if(!exceptionNotCatched) {
        				// if an exception occurs during the reading we break from the main while(exception_not_catched)
        				Log.d(tag, "An exception occurred => break;");
        				break;
        			}
    				
    			} // END if(attachNumber>0)	        
    			
    			
    			Log.d("IOEpicService", "sent checksum = " + crcCheck);
    			Log.d("IOEpicService", "computed checksum = " + checksum.getValue());
    			// TODO CHECK MD5 CRC
    			if(checksum.getValue()==crcCheck) {
    				Log.d(tag, "checksum ok!!!");
	        		dbHelper.addContent(msgId, msgExpTime, msgLat, msgLon, msgAlt, msgGeoSpan, 
	        	    		msgCategories, 
	        	    		msgCreatorId, // creator ID
	        	    		msgTitle, msgContent, attach_extension_array, attach_path_array,
	        	    		hopNumber + 1,
	        	    		yourUsername, // carrier ID
	        	    		deliveryTime, deliveryLat, deliveryLon, deliveryAlt, 
	        	    		CurrentUser.getMd5ID(getApplicationContext()), // logged ID  
	        	    		false, false, false, false,//readUnread, msgDeleted, synchNotsynch, updated,
	        	    		deferred_sending, 
	        	    		0, // (or t_now_in_seconds) ltc_time  
	        	    		0, // number of transmitted copies
	        	    		rxRate,
	        	    		msgCreatorNick, rxRate, approximateMsgSize, crcCheck);
	        		// Content packet reception complete
	    			Log.d(tag, "Content reception complete!");
	        		Log.d(tag, "New Epic message inserted in DB");
    			}
    			else {
    				Log.d(tag, "checksum failed!!!");
    			}
    			dbHelper.close();
    		}	
    		return exceptionNotCatched;
    	}
        //##############################################################################################################################
        //##############################################################################################################################
        
        //###############################
        //# COMMUNICATION MASTER METHOD #
        //###############################
    	public void communicationMaster(){
    		String your_username;
    		String your_pref_cat;
    		double delivery_lat = 0;
    		double delivery_lon = 0;
    		double delivery_alt = 0;
    		long delivery_time = 0;
    		boolean emptyProposal = false;
    		boolean exception_not_catched = true;
    		boolean checkVersionAndType = true;
    		
    		if(mmSocket != null){
    			
    			// Keep listening to the InputStream while connected
    			
	            while(exception_not_catched) {
	            	
	            	if(communicationTimer != null) {
	            		communicationTimer.cancel();
	            		communicationTimer = null;
	            	}
	            	communicationTimer = new Timer();
	            	communicationTimer.schedule(new CommunicationTimerElapsedTask(), STOP_COMMUNICATION_PERIOD);
	            	
	            	//#################
	                // info packet TX #
	            	//#################
	            	infobufferTX = createInfoPacket();
	            	write(infobufferTX);
	            	Log.d("ConnectedThread, communicationMaster()", "Info packet transmitted");
	    			
	            	//#################
	                // info packet RX #
	            	//#################
	            	int i = 0;
	            	
	    			int nOfByte = 0;
	    			int nob = 0;
	    			int byteOffset = 0;
	    			while(nOfByte < INFO_PACKET_LENGTH) {
	    				nob = read(infobufferRX, byteOffset);
	    				if(nob==-2) {
	    					Log.d("communicationMaster()", "Connection lost during info pck reception");
	    					exception_not_catched = false;
	    					startListeningTimer();
	    					break;
	    				}
	    				else if(nob==-1) {
	    					Log.d("ConnectedThread", "End of inputStram reached!!!");
	    					break;
	    				}
	    				else {
	    					nOfByte = nOfByte + nob;
	    					byteOffset = nOfByte;
	    				}
	    			}
	    			if(!exception_not_catched) {
	    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
	    				Log.d("ConnectedThread, communicationMaster()", "An exception occurred => break;");
	    				break;
	    			}
	    			if(checkVersionAndType) {
    					int typerx = (infobufferRX[0] & 0xF0)>>4;
    	        		int versionrx = (infobufferRX[0] & 0x0F);
    	        		if(typerx != EpicVersionSettings.infoType) {
    	        			//TODO Manage incorrect type packet reception
    	        			Log.d("ConnectedThread, communicationMaster()", "Wrong pck type: expected = " + 
    	        			EpicVersionSettings.infoType + " received = " + typerx);
    	        		}
    	        		else
    	        		{
    	        			Log.d("ConnectedThread, communicationMaster()", "Info packet received");
    	        		}
    				}
	    			
	    			// retrieve information from info pck
	    			String[] infoPacketRX = getInfoPacket(infobufferRX);
	    			
	    			// username of the found Epic user
	    			your_username = infoPacketRX[0];
	    			// pref categories of the connected Epic user
	    			your_pref_cat = infoPacketRX[1];
	    			
	    			Location loc = null;
					try {
						// TODO Check if the refreshLocation() operation is time consuming and, if so, find a solution to be quick
						loc = (Location) mILocationEpicService.refreshLocation();
					}
					catch (RemoteException e) {
						Log.d("ConnectedThread, communicationMaster()", "Not able to retrieve actual position");
						e.printStackTrace();
					}
					if(loc!=null) {
						delivery_lat = loc.getLatitude();
						delivery_lon = loc.getLongitude();
						delivery_alt = loc.getAltitude();
					}
					else {
						// TODO
						// before setting these values to 0 check if the user I'm connected has a fresh position information
						// TODO 
						// change info pck in order to add the position information if available
						delivery_lat = 0;
						delivery_lon = 0;
						delivery_alt = 0;
					}
					
					Date now = new Date();
					delivery_time = now.getTime()/1000;
					EpicContentManipulation cm = new EpicContentManipulation(mContext);
					// sort the contents based on user, his preferences, the actual position and time
	    			contentStack = cm.computeMsgPriority(your_username, your_pref_cat, delivery_lat, delivery_lon);
	    			
	    			if(contentStack.empty()) {
	    				Log.d("ConnectedThread, communicationMaster()", "Proposal stack empty after sorting");
	    				emptyProposal = true;
	    			}
	    			else {
	    				Log.d("ConnectedThread, communicationMaster()", "Proposal stack not empty");
	    				emptyProposal = false;
	    			}
					
					//#####################
	                // Communication CORE #
	            	//#####################
	    			if(contentStack != null && exception_not_catched) {
	    				
	    				while(exception_not_catched) {
	    				
	    					if(communicationTimer != null) {
	    	            		communicationTimer.cancel();
	    	            		communicationTimer = null;
	    	            	}
	    	            	communicationTimer = new Timer();
	    	            	communicationTimer.schedule(new CommunicationTimerElapsedTask(), STOP_COMMUNICATION_PERIOD);
	    					
		    				if(!contentStack.empty()) {
		    					
		    					do{
		    						//##########################
		    		                // meta proposal packet TX #
		    		            	//##########################
		    						meta_proposal_bufferTX = createMetaProposalPacket();
		    						write(meta_proposal_bufferTX);
		    						Log.d("ConnectedThread, communicationMaster()", "Meta poroposal packet transmitted");
		    						
		    						//######################
		    		                // meta echo packet RX #
		    		            	//######################
		    						nOfByte = 0;
		    		    			nob = 0;
		    		    			byteOffset = 0;
		    		    			while(nOfByte < META_ECHO_PACKET_LENGTH) {
		    		    				nob = read(meta_echo_bufferRX, byteOffset);
		    		    				if(nob==-2) {
		    		    					Log.d("communicationMaster()", "Connection lost during meta echo pck reception");
		    		    					exception_not_catched = false;
		    		    					startListeningTimer();
		    		    					break;
		    		    				}
		    		    				else if(nob==-1) {
		    		    					Log.d("ConnectedThread", "End of inputStram reached!!!");
		    		    					break;
		    		    				}
		    		    				else {
		    		    					nOfByte = nOfByte + nob;
		    		    					byteOffset = nOfByte;
		    		    				}
		    		    			}
		    		    			if(!exception_not_catched) {
		    		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
		    		    				Log.d("ConnectedThread, communicationMaster()", "An exception occurred => break;");
		    		    				break;
		    		    			}
		    		    			if(checkVersionAndType) {
	    		    					int typerx = (meta_echo_bufferRX[0] & 0xF0)>>4;
	    		    	        		int versionrx = (meta_echo_bufferRX[0] & 0x0F);
	    		    	        		if(typerx != EpicVersionSettings.metaEchoType) {
	    		    	        			//TODO Manage incorrect type packet reception
	    		    	        			Log.d("ConnectedThread, communicationMaster()", "Wrong pck type: expected = " + 
	    		    	        			EpicVersionSettings.metaEchoType + " received = " + typerx);
	    		    	        		}
	    		    	        		else
	    		    	        		{
	    		    	        			Log.d("ConnectedThread, communicationMaster()", "Meta echo packet received");
	    		    	        		}
	    		    				}
		    		    			
		    		    			// retrieve information from meta echo pck
		    		    			if(meta_echo_bufferRX[2]==0){
		    		    				// proposals are not accepted
		    		    				Log.d("ConnectedThread, communicationMaster()", "My proposals are not accepted");
		    		    			}
		    		    			else {
		    		    				// contents TX
		    		    				// TODO Since we tx a content pck at a time, be sure that the receiver reads the buffer 
		    		    				// and performs the require operation before sending the next content pck
		    		    				
		    		    				Log.d("ConnectedThread, communicationMaster()", "Some proposal is accepted");
		    		    				
		    		    				int q = 0;
		    		    				if(meta_echo_bufferRX[2]<0){
		    		    					q = meta_echo_bufferRX[2] + 256;
		    		    				}
		    		    				else{
		    		    					q = meta_echo_bufferRX[2];
		    		    				}
		    		    				String acceptedMeta = Integer.toBinaryString(q);
		    		    				if(acceptedMeta.length()<8){
		    		    					String tmp_str = "";
		    	                            String zero_str = "0";
		    	                            for(int ii=0; ii<(8-acceptedMeta.length()); ii++) {
		    	                                    tmp_str = tmp_str + zero_str;
		    	                            }
		    	                            acceptedMeta = tmp_str + acceptedMeta;
		    		    				}
		    		    				for(i = 0; i<8; i++){
		    		    					char b = acceptedMeta.charAt(i);
		    		    					if(b == '1'){
		    		    						//####################
		    		    		                // content packet TX #
		    		    		            	//####################
		    		    						content_bufferTX = createContentPacket(tmpEMId[i].msg_id);
		    		    						write(content_bufferTX);
		    		    						Log.d("ConnectedThread, communicationMaster()", "Msg: " + tmpEMId[i].msg_id + " transmitted");
		    		    						dbHelper.open();
		    		    						int notc = dbHelper.updateNumberOfTxCopies(tmpEMId[i].msg_id);
		    		    						long ltcTime = dbHelper.updateLastTxCopyTime(tmpEMId[i].msg_id);
		    		    						dbHelper.close();
		    		    						Log.d("ConnectedThread, communicationMaster()", 
		    		    								"number of tx copies, time of last tx copy = " + notc + ", " + ltcTime);
		    		    					}
		    		    				}
		    		    			}
		    		    			
		    		    			//####################################################################################################
			    					// if both you and me have no more contents (resp. hasMore==false and meta_proposal_bufferTX[50]==0) #
		    		    			// close connection																					 #
			    					//####################################################################################################
		    		    			if(!hasMore && meta_proposal_bufferTX[50] == 0) {
		    		    				Log.d("ConnectedThread, communicationMaster()", "We both have no more contents of interest");
		    		    				// close thread and socket
		    		    				// call listeningTimer()
		    		    				try {mmSocket.close();} catch (IOException e) {e.printStackTrace();}
										try {mmInStream.close();} catch (IOException e) {e.printStackTrace();}
										try {mmOutStream.close();} catch (IOException e) {e.printStackTrace();}
										// TODO semantic issue: exception_not_catched not appropriate 
										// use a different flag
										exception_not_catched = false; 
				    					startListeningTimer();
				    					break;
		    		    			}
		    		    			if(!exception_not_catched) {
		    		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
		    		    				Log.d("ConnectedThread, communicationMaster()", "An exception occurred => break;");
		    		    				break;
		    		    			}
		    					} while(!hasMore);
		    					
		    				} // END if(!contentStack.empty())
		    				else { 
		    					if(emptyProposal && exception_not_catched) {
		    						emptyProposal = false;
		    						//############################################################
		    						// contentStack is not been depleted but found already empty #
		    						//############################################################
		    						// meta proposal creation and TX 
		    						// TODO check to create a pck with no valid msg_id and with meta_proposal_bufferTX[50] = 0; 
		    						meta_proposal_bufferTX = createMetaProposalPacket();
		    						
		    						//##########################
		    		                // meta proposal packet TX #
		    		            	//##########################
		    						write(meta_proposal_bufferTX);
		    						Log.d("ConnectedThread, communicationMaster()", 
		    								"No original contents for you: empty meta proposal packet transmitted");
		    						
		    						//meta echo RX and parsing
		    						nOfByte = 0;
		    		    			nob = 0;
		    		    			byteOffset = 0;
		    		    			while(nOfByte < META_ECHO_PACKET_LENGTH) {
		    		    				nob = read(meta_echo_bufferRX, byteOffset);
		    		    				if(nob==-2) {
		    		    					Log.d("communicationMaster()", "Connection lost during meta echo pck reception");
		    		    					exception_not_catched = false;
		    		    					startListeningTimer();
		    		    					break;
		    		    				}
		    		    				else if(nob==-1) {
		    		    					Log.d("ConnectedThread", "End of inputStram reached!!!");
		    		    					break;
		    		    				}
		    		    				else {
		    		    					nOfByte = nOfByte + nob;
		    		    					byteOffset = nOfByte;
		    		    				}
		    		    			}
		    		    			if(!exception_not_catched) {
		    		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
		    		    				Log.d("ConnectedThread, communicationMaster()", "An exception occurred => break;");
		    		    				break;
		    		    			}
		    		    			if(checkVersionAndType) {
	    		    					int typerx = (meta_echo_bufferRX[0] & 0xF0)>>4;
	    		    	        		int versionrx = (meta_echo_bufferRX[0] & 0x0F);
	    		    	        		if(typerx != EpicVersionSettings.metaEchoType) {
	    		    	        			//TODO Manage incorrect type packet reception
	    		    	        			Log.d("ConnectedThread, communicationMaster()", "Wrong pck type: expected = " + 
	    		    	        			EpicVersionSettings.metaEchoType + " received = " + typerx);
	    		    	        		}
	    		    	        		else
	    		    	        		{
	    		    	        			Log.d("ConnectedThread, communicationMaster()", "Meta echo packet received");
	    		    	        		}
	    		    				}
		    		    			
		    		    			if(meta_echo_bufferRX[2]==0){
		    		    				// proposals are not accepted
		    		    				Log.d("communicationMaster", "Proposals not accepted because no valid proposals were sent");
		    		    			}
		    		    			else {
		    		    				Log.d("communicationMaster", "Something went wrong: I should receive meta_echo.reserverd = 0");
		    		    			}
		    					}
		    					
		    					//####################################################################################################
		    					// if both you and me have no more contents (resp. hasMore==false and meta_proposal_bufferTX[50]==0) #
	    		    			// close connection																					 #
		    					//####################################################################################################
		    					if(!hasMore && meta_proposal_bufferTX[50] == 0) {
		    						Log.d("ConnectedThread, communicationMaster()", "We both have no more contents of interest");
	    		    				// close thread and socket
	    		    				// call listeningTimer()
	    		    				try {mmSocket.close();} catch (IOException e) {e.printStackTrace();}
									try {mmInStream.close();} catch (IOException e) {e.printStackTrace();}
									try {mmOutStream.close();} catch (IOException e) {e.printStackTrace();}
									// TODO semantic issue: exception_not_catched not appropriate 
									// use a different flag
									exception_not_catched = false; 
			    					startListeningTimer();
			    					break;
	    		    			}
	    		    			if(!exception_not_catched) {
	    		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
	    		    				Log.d("ConnectedThread, communicationMaster()", "An exception occurred => break;");
	    		    				break;
	    		    			}
		    				}
		    				
		    				
		    				//##########################
			                // meta proposal packet RX #
			            	//##########################
		    				nOfByte = 0;
			    			nob = 0;
			    			byteOffset = 0;
			    			while(nOfByte < META_PROP_PACKET_LENGTH) {
			    				nob = read(meta_proposal_bufferRX, byteOffset);
			    				if(nob==-2) {
			    					Log.d("communicationMaster()", "Connection lost during meta proposal pck reception");
			    					exception_not_catched = false;
			    					startListeningTimer();
			    					break;
			    				}
			    				else if(nob==-1) {
			    					Log.d("ConnectedThread", "End of inputStram reached!!!");
			    					break;
			    				}
			    				else {
			    					nOfByte = nOfByte + nob;
			    					byteOffset = nOfByte;
			    				}
		    				}
		    				if(meta_proposal_bufferRX[50]!=0) {
		    					hasMore = true; 
		    				}
		    				else{
		    					hasMore = false;
		    				}
		    				if(!exception_not_catched) {
			    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
			    				Log.d("ConnectedThread, communicationMaster()", "An exception occurred => break;");
			    				break;
			    			}
		    				if(checkVersionAndType) {
		    					int typerx = (meta_proposal_bufferRX[0] & 0xF0)>>4;
		    	        		int versionrx = (meta_proposal_bufferRX[0] & 0x0F);
		    	        		if(typerx != EpicVersionSettings.metaPropType) {
		    	        			//TODO Manage incorrect type packet reception
		    	        			Log.d("ConnectedThread, communicationMaster()", "Wrong pck type: expected = " + 
		    	        			EpicVersionSettings.metaPropType + " received = " + typerx);
		    	        		}
		    	        		else
		    	        		{
		    	        			Log.d("ConnectedThread, communicationMaster()", "Meta proposal packet received");
		    	        		}
		    				}
		    				
		    				//######################
			                // meta echo packet TX #
			            	//######################
		    				// result = {meta_echo_bufferTX, number of accepted metadata}
		    				Object[] result = createMetaEchoPacket(meta_proposal_bufferRX);
		    				meta_echo_bufferTX = (byte[])result[0];
		    				String acceptedContents_str = (String) result[1];
		    				// keep track of the number of contents I accepted 
		    				int acceptedContents = Integer.parseInt(acceptedContents_str, 10);
		    				write(meta_echo_bufferTX);
		    				Log.d("ConnectedThread, communicationMaster()", "Meta echo packet transmitted");
		    				
		    				
		    				//####################
			                // content packet RX #
			            	//####################
		    				if(acceptedContents > 0) {
		    					
		    					// TODO Since we rx a content pck at a time, be sure that the receiver gives us the time
		    					// to read the buffer and perform the require operation before he sends the next content pck
		    					
		    					exception_not_catched = contentPacketRx("ConnectedThread, communicationMaster()", checkVersionAndType, 
		    							exception_not_catched, 
		    							acceptedContents,
		    			        		your_username, delivery_time, delivery_lat, delivery_lon, delivery_alt);
		    					
		    				} // END if(acceptedContents > 0)
	    				
	    				} // END while(exception_not_catched) {
	    				if(!exception_not_catched) {
		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
		    				Log.d("ConnectedThread, communicationMaster()", "An exception occurred => break;");
		    				break;
		    			}
		    			
	    			} // END if(contentStack != null)
	    			else {
	    				// contentStack == null
	    				Log.d("ConnectedThread, communicationMaster()", "Stack == null! Strange behavior!");
	    				exception_not_catched = false;
    					startListeningTimer();
    					break;
	    			}
	            } // END while(exception_not_catched)
    		} // END if(mmSocket != null)
    	} // END communicationMaster()
        
    	
    	//##############################
        //# COMMUNICATION SLAVE METHOD #
        //##############################
		private void communicationSlave() {
			String your_username;
    		String your_pref_cat;
    		double delivery_lat = 0;
    		double delivery_lon = 0;
    		double delivery_alt = 0;
    		long delivery_time = 0;
    		boolean emptyProposal = false;
    		boolean exception_not_catched = true;
    		boolean checkVersionAndType = true;
    		
    		if(mmSocket != null){
    			
    			// Keep listening to the InputStream while connected
    			
	            while(exception_not_catched) {
	            	
	            	if(communicationTimer != null) {
	            		communicationTimer.cancel();
	            		communicationTimer = null;
	            	}
	            	communicationTimer = new Timer();
	            	communicationTimer.schedule(new CommunicationTimerElapsedTask(), STOP_COMMUNICATION_PERIOD);
	    			
	            	//#################
	                // info packet RX #
	            	//#################
	    			int i = 0;
	    			int nOfByte = 0;
	    			int nob = 0;
	    			int byteOffset = 0;
	    			while(nOfByte < INFO_PACKET_LENGTH) {
	    				nob = read(infobufferRX, byteOffset);
	    				if(nob==-2) {
	    					Log.d("communicationSlave()", "Connection lost during info pck reception");
	    					exception_not_catched = false;
	    					startListeningTimer();
	    					break;
	    				}
	    				else if(nob==-1) {
	    					Log.d("ConnectedThread", "End of inputStram reached!!!");
	    					break;
	    				}
	    				else {
	    					nOfByte = nOfByte + nob;
	    					byteOffset = nOfByte;
	    				}
	    			}
	    			if(!exception_not_catched) {
	    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
	    				Log.d("ConnectedThread, communicationSlave()", "An exception occurred => break;");
	    				break;
	    			}
	    			if(checkVersionAndType) {
    					int typerx = (infobufferRX[0] & 0xF0)>>4;
    	        		int versionrx = (infobufferRX[0] & 0x0F);
    	        		if(typerx != EpicVersionSettings.infoType) {
    	        			//TODO Manage incorrect type packet reception
    	        			Log.d("ConnectedThread, communicationSlave()", "Wrong pck type: expected = " + 
    	        			EpicVersionSettings.infoType + " received = " + typerx);
    	        		}
    	        		else
    	        		{
    	        			Log.d("ConnectedThread, communicationSlave()", "Info packet received");
    	        		}
    				}
	    			
	    			// retrieve information from info pck
	    			String[] infoPacketRX = getInfoPacket(infobufferRX);
	    			
	    			// username of the found Epic user
	    			your_username = infoPacketRX[0];
	    			// pref categories of the found Epic user
	    			your_pref_cat = infoPacketRX[1];
	    			
	    			Location loc = null;
					try {
						// TODO Check if the refreshLocation() operation is time consuming and, if so, find a solution to be quick
						loc = (Location) mILocationEpicService.refreshLocation();
					}
					catch (RemoteException e) {
						Log.d("ConnectedThread, communicationSlave()", "Not able to retrieve actual position");
						e.printStackTrace();
					}
					
					EpicContentManipulation cm = new EpicContentManipulation(mContext);
					// sort the contents based on user, his preferences, the actual position and time
					if(loc!=null) {
						delivery_lat = loc.getLatitude();
						delivery_lon = loc.getLongitude();
						delivery_alt = loc.getAltitude();
					}
					else {
						delivery_lat = 0;
						delivery_lon = 0;
						delivery_alt = 0;
					}
					
					Date now = new Date();
					delivery_time = now.getTime()/1000;
					
	    			contentStack = cm.computeMsgPriority(your_username, your_pref_cat, delivery_lat, delivery_lon);
	    			
	    			if(contentStack.empty()) {
	    				Log.d("ConnectedThread, communicationSlave()", "Proposal stack empty after sorting");
	    				emptyProposal = true;
	    			}
	    			else {
	    				Log.d("ConnectedThread, communicationSlave()", "Proposal stack not empty");
	    				emptyProposal = false;
	    			}
					
					//#################
	                // info packet TX #
	            	//#################
	            	infobufferTX = createInfoPacket();
	            	write(infobufferTX);
	            	Log.d("ConnectedThread, communicationSlave()", "Info packet transmitted");
	            	
	            	
	            	//#####################
	                // Communication CORE #
	            	//#####################
	    			if(contentStack != null && exception_not_catched) {
	    				
	    				while(exception_not_catched) {
	    					
	    					if(communicationTimer != null) {
	    	            		communicationTimer.cancel();
	    	            		communicationTimer = null;
	    	            	}
	    	            	communicationTimer = new Timer();
	    	            	communicationTimer.schedule(new CommunicationTimerElapsedTask(), STOP_COMMUNICATION_PERIOD);
	    				
		    				//##########################
			                // meta proposal packet RX #
			            	//##########################
		    				i = 0;
		    				nOfByte = 0;
			    			nob = 0;
			    			byteOffset = 0;
			    			while(nOfByte < META_PROP_PACKET_LENGTH) {
			    				nob = read(meta_proposal_bufferRX, byteOffset);
			    				if(nob==-2) {
			    					Log.d("communicationSlave()", "Connection lost during meta proposal pck reception");
			    					exception_not_catched = false;
			    					startListeningTimer();
			    					break;
			    				}
			    				else if(nob==-1) {
			    					Log.d("ConnectedThread", "End of inputStram reached!!!");
			    					break;
			    				}
			    				else {
			    					nOfByte = nOfByte + nob;
			    					byteOffset = nOfByte;
			    				}
		    				}
		    				if(meta_proposal_bufferRX[50]!=0) {
		    					hasMore = true; 
		    				}
		    				else{
		    					hasMore = false;
		    				}
		    				if(!exception_not_catched) {
			    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
			    				Log.d("ConnectedThread, communicationSlave()", "An exception occurred => break;");
			    				break;
			    			}
		    				if(checkVersionAndType) {
		    					int typerx = (meta_proposal_bufferRX[0] & 0xF0)>>4;
		    	        		int versionrx = (meta_proposal_bufferRX[0] & 0x0F);
		    	        		if(typerx != EpicVersionSettings.metaPropType) {
		    	        			//TODO Manage incorrect type packet reception
		    	        			Log.d("ConnectedThread, communicationSlave()", "Wrong pck type: expected = " + 
		    	        			EpicVersionSettings.metaPropType + " received = " + typerx);
		    	        		}
		    	        		else
		    	        		{
		    	        			Log.d("ConnectedThread, communicationSlave()", "Meta proposal packet received");
		    	        		}
		    				}
		    				
		    				//######################
			                // meta echo packet TX #
			            	//######################
		    				// result = {meta_echo_bufferTX, number of accepted metadata}
		    				Object[] result = createMetaEchoPacket(meta_proposal_bufferRX);
		    				meta_echo_bufferTX = (byte[])result[0];
		    				String acceptedContents_str = (String) result[1];
		    				// keep track of the number of contents I accepted 
		    				int acceptedContents = Integer.parseInt(acceptedContents_str, 10);
		    				write(meta_echo_bufferTX);
		    				Log.d("ConnectedThread, communicationSlave()", "Meta echo packet transmitted");
		    				
		    				
		    				//####################
			                // content packet RX #
			            	//####################
		    				if(acceptedContents > 0) {

		    					// TODO Since we rx a content pck at a time, be sure that the receiver gives us the time
		    					// to read the buffer and perform the require operation before he sends the next content pck
		    					
		    					exception_not_catched = contentPacketRx("ConnectedThread, communicationSlave()", checkVersionAndType, 
		    							exception_not_catched, 
		    							acceptedContents,
		    			        		your_username, delivery_time, delivery_lat, delivery_lon, delivery_alt);
		    					
		    				} // END if(acceptedContents > 0)
		    				
		    				
		    				if(!contentStack.empty()) {
		    					
		    					do{
		    						//##########################
		    		                // meta proposal packet TX #
		    		            	//##########################
		    						meta_proposal_bufferTX = createMetaProposalPacket();
		    						write(meta_proposal_bufferTX);
		    						Log.d("ConnectedThread, communicationSlave()", "Meta poroposal packet transmitted");
		    						
		    						//######################
		    		                // meta echo packet RX #
		    		            	//######################
		    						nOfByte = 0;
		    		    			nob = 0;
		    		    			byteOffset = 0;
		    		    			while(nOfByte < META_ECHO_PACKET_LENGTH) {
		    		    				nob = read(meta_echo_bufferRX, byteOffset);
		    		    				if(nob==-2) {
		    		    					Log.d("communicationSlave()", "Connection lost during meta echo pck reception");
		    		    					exception_not_catched = false;
		    		    					startListeningTimer();
		    		    					break;
		    		    				}
		    		    				else if(nob==-1) {
		    		    					Log.d("ConnectedThread", "End of inputStram reached!!!");
		    		    					break;
		    		    				}
		    		    				else {
		    		    					nOfByte = nOfByte + nob;
		    		    					byteOffset = nOfByte;
		    		    				}
		    		    			}
		    		    			if(!exception_not_catched) {
		    		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
		    		    				Log.d("ConnectedThread, communicationSlave()", "An exception occurred => break;");
		    		    				break;
		    		    			}
		    		    			if(checkVersionAndType) {
	    		    					int typerx = (meta_echo_bufferRX[0] & 0xF0)>>4;
	    		    	        		int versionrx = (meta_echo_bufferRX[0] & 0x0F);
	    		    	        		if(typerx != EpicVersionSettings.metaEchoType) {
	    		    	        			//TODO Manage incorrect type packet reception
	    		    	        			Log.d("ConnectedThread, communicationSlave()", "Wrong pck type: expected = " + 
	    		    	        			EpicVersionSettings.metaEchoType + " received = " + typerx);
	    		    	        		}
	    		    	        		else
	    		    	        		{
	    		    	        			Log.d("ConnectedThread, communicationSlave()", "Meta echo packet received");
	    		    	        		}
	    		    				}
		    		    			
		    		    			// retrieve information from meta echo pck
		    		    			if(meta_echo_bufferRX[2]==0){
		    		    				// proposals are not accepted
		    		    				Log.d("ConnectedThread, communicationSlave()", "My proposals are not accepted");
		    		    			}
		    		    			else {
		    		    				// contents TX
		    		    				// TODO Since we tx a content pck at a time, be sure that the receiver reads the buffer 
		    		    				// and performs the require operation before sending the next content pck
		    		    				
		    		    				Log.d("ConnectedThread, communicationSlave()", "Some proposal is accepted");
		    		    				
		    		    				int q = 0;
		    		    				if(meta_echo_bufferRX[2]<0){
		    		    					q = meta_echo_bufferRX[2] + 256;
		    		    				}
		    		    				else{
		    		    					q = meta_echo_bufferRX[2];
		    		    				}
		    		    				String acceptedMeta = Integer.toBinaryString(q);
		    		    				if(acceptedMeta.length()<8){
		    		    					String tmp_str = "";
		    	                            String zero_str = "0";
		    	                            for(int ii=0; ii<(8-acceptedMeta.length()); ii++) {
		    	                                    tmp_str = tmp_str + zero_str;
		    	                            }
		    	                            acceptedMeta = tmp_str + acceptedMeta;
		    		    				}
		    		    				for(i =0; i<8; i++){
		    		    					char b = acceptedMeta.charAt(i);
		    		    					if(b == '1'){
		    		    						//####################
		    		    		                // content packet TX #
		    		    		            	//####################
		    		    						content_bufferTX = createContentPacket(tmpEMId[i].msg_id);
		    		    						write(content_bufferTX);
		    		    						Log.d("ConnectedThread, communicationSlave()", "Msg: " + tmpEMId[i].msg_id + " transmitted");
		    		    						dbHelper.open();
		    		    						int notc = dbHelper.updateNumberOfTxCopies(tmpEMId[i].msg_id);
		    		    						long ltcTime = dbHelper.updateLastTxCopyTime(tmpEMId[i].msg_id);
		    		    						dbHelper.close();
		    		    						Log.d("ConnectedThread, communicationSlave()", 
		    		    								"number of tx copies, time of last tx copy = " + notc + ", " + ltcTime);
		    		    					}
		    		    				}
		    		    			}
		    		    			
		    		    			//####################################################################################################
			    					// if both you and me have no more contents (resp. hasMore==false and meta_proposal_bufferTX[50]==0) #
		    		    			// close connection																					 #
			    					//####################################################################################################
		    		    			if(!hasMore && meta_proposal_bufferTX[50] == 0) {
		    		    				Log.d("ConnectedThread, communicationSlave()", "We both have no more contents of interest");
		    		    				// close thread and socket
		    		    				// call listeningTimer()
		    		    				try {mmSocket.close();} catch (IOException e) {e.printStackTrace();}
										try {mmInStream.close();} catch (IOException e) {e.printStackTrace();}
										try {mmOutStream.close();} catch (IOException e) {e.printStackTrace();}
										// TODO semantic issue: exception_not_catched not appropriate 
										// use a different flag
										exception_not_catched = false; 
				    					startListeningTimer();
				    					break;
		    		    			}
		    		    			if(!exception_not_catched) {
		    		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
		    		    				Log.d("ConnectedThread, communicationSlave()", "An exception occurred => break;");
		    		    				break;
		    		    			}
		    					} while(!hasMore);
		    					
		    				} // END if(!contentStack.empty())
		    				else { 
		    					if(emptyProposal && exception_not_catched) {
		    						emptyProposal = false;
		    						//############################################################
		    						// contentStack is not been depleted but found already empty #
		    						//############################################################
		    						// meta proposal creation and TX 
		    						// TODO check to create a pck with no valid msg_id and with meta_proposal_bufferTX[50] = 0; 
		    						meta_proposal_bufferTX = createMetaProposalPacket();
		    						
		    						//##########################
		    		                // meta proposal packet TX #
		    		            	//##########################
		    						write(meta_proposal_bufferTX);
		    						Log.d("ConnectedThread, communicationSlave()", 
		    								"No original contents for you: empty meta proposal packet transmitted");
		    						
		    						//meta echo RX and parsing
		    						nOfByte = 0;
		    		    			nob = 0;
		    		    			byteOffset = 0;
		    		    			while(nOfByte < META_ECHO_PACKET_LENGTH) {
		    		    				nob = read(meta_echo_bufferRX, byteOffset);
		    		    				if(nob==-2) {
		    		    					Log.d("communicationSlave()", "Connection lost during meta echo pck reception");
		    		    					exception_not_catched = false;
		    		    					startListeningTimer();
		    		    					break;
		    		    				}
		    		    				else if(nob==-1) {
		    		    					Log.d("ConnectedThread", "End of inputStram reached!!!");
		    		    					break;
		    		    				}
		    		    				else {
		    		    					nOfByte = nOfByte + nob;
		    		    					byteOffset = nOfByte;
		    		    				}
		    		    			}
		    		    			if(!exception_not_catched) {
		    		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
		    		    				Log.d("ConnectedThread, communicationSlave()", "An exception occurred => break;");
		    		    				break;
		    		    			}
		    		    			if(checkVersionAndType) {
	    		    					int typerx = (meta_echo_bufferRX[0] & 0xF0)>>4;
	    		    	        		int versionrx = (meta_echo_bufferRX[0] & 0x0F);
	    		    	        		if(typerx != EpicVersionSettings.metaEchoType) {
	    		    	        			//TODO Manage incorrect type packet reception
	    		    	        			Log.d("ConnectedThread, communicationSlave()", "Wrong pck type: expected = " + 
	    		    	        			EpicVersionSettings.metaEchoType + " received = " + typerx);
	    		    	        		}
	    		    	        		else
	    		    	        		{
	    		    	        			Log.d("ConnectedThread, communicationSlave()", "Meta echo packet received");
	    		    	        		}
	    		    				}
		    		    			
		    		    			if(meta_echo_bufferRX[2]==0){
		    		    				// proposals are not accepted
		    		    				Log.d("communicationSlave", "Proposals not accepted because no valid proposals were sent");
		    		    			}
		    		    			else {
		    		    				Log.d("communicationSlave", "Something went wrong: I should receive meta_echo.reserverd = 0");
		    		    			}
		    					}
		    					
		    					//####################################################################################################
		    					// if both you and me have no more contents (resp. hasMore==false and meta_proposal_bufferTX[50]==0) #
	    		    			// close connection																					 #
		    					//####################################################################################################
		    					if(!hasMore && meta_proposal_bufferTX[50] == 0) {
		    						Log.d("ConnectedThread, communicationSlave()", "We both have no more contents of interest");
	    		    				// close thread and socket
	    		    				// call listeningTimer()
	    		    				try {mmSocket.close();} catch (IOException e) {e.printStackTrace();}
									try {mmInStream.close();} catch (IOException e) {e.printStackTrace();}
									try {mmOutStream.close();} catch (IOException e) {e.printStackTrace();}
									// TODO semantic issue: exception_not_catched not appropriate 
									// use a different flag
									exception_not_catched = false; 
			    					startListeningTimer();
			    					break;
	    		    			}
	    		    			if(!exception_not_catched) {
	    		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
	    		    				Log.d("ConnectedThread, communicationSlave()", "An exception occurred => break;");
	    		    				break;
	    		    			}
		    				}
	    				} // END while(exception_not_catched) {
	    				if(!exception_not_catched) {
		    				// if an exception occurs during the reading we break from the main while(exception_not_catched)
		    				Log.d("ConnectedThread, communicationMaster()", "An exception occurred => break;");
		    				break;
		    			}
	    				
	    			} // END if(contentStack != null)
	    			else {
	    				// contentStack == null
	    				Log.d("ConnectedThread, communicationMaster()", "Stack == null! Strange behavior!");
	    				exception_not_catched = false;
    					startListeningTimer();
    					break;
	    			}
	            } // END while(true)
    		} // END if(mmSocket != null)
    	} // END communicationSlave()
		
        
		//#########################################################
        // Method used to create INFO PACKET
        // TODO Check the correctness of this method
        private byte[] createInfoPacket(){
        	byte[] infoPacket = new byte[INFO_PACKET_LENGTH];
        	int version = EpicVersionSettings.commVersion;
        	int type = EpicVersionSettings.infoType * 16;
        	char blank = ' '; 
        	infoPacket[0] = (byte)(version + type);
        	
        	CurrentUser.readCurrentUserSettings(getApplicationContext());
        	String user_account_id = CurrentUser.getMd5ID(getApplicationContext());
        	int user_length = user_account_id.length();
        	for(int i = 0; i< 16; i++){
        		if(i < user_length){
        			byte a = (byte) user_account_id.charAt(i);
        			infoPacket[i+1] = a;
        		}else{		
        			byte a = (byte) blank;
        			infoPacket[i+1] = a;
        		}
        	}
        	// 0 = not checked, 1 = liked, 2 = banned
        	String user_pref_cat = CurrentUser.getPrefCategories();
        	int cat_val_1 = 0;
        	int cat_val_2 = 0;
        	for(int i = 0; i< 8; i++){
        		if(user_pref_cat.charAt(i) == '1') {
        			cat_val_1 = (int) (cat_val_1 + Math.pow(2, 8-i-1));
        		}
        	}
        	for(int i = 8; i< 16; i++){
        		if(user_pref_cat.charAt(i) == '1') {
        			cat_val_2 = (int) (cat_val_2 + Math.pow(2, 16-i-1));
        		}
        	}
        	infoPacket[17] = (byte) cat_val_1;
        	infoPacket[18] = (byte) cat_val_2;
        	
        	return infoPacket;
        }
        
        // Method used to retrieve the user id and his categories' preferences 
        // TODO Check the correctness of this method
        public String[] getInfoPacket(byte[] infopacket){
        	byte btx = infopacket[0];
        	int typerx = (btx & 0xF0)>>4;
    		int versionrx = (btx & 0x0F);
        	
        	String[] result = new String[2];
        	String username = "";
        	String pref_cat_1 = "";
        	String pref_cat_2 = "";
        	char blank = ' ';
        	for(int i = 1; i<INFO_PACKET_LENGTH; i++){
        		if(i<17){
        			char c = (char) infopacket[i];
        			// TODO Check the correctness of using == with char
        			if(c==blank) {
        				// do nothing
        			}
        			else {
        				username = username + c;
        			}
        		}
        		else if(i==17) {
        			int q;
        			if(infopacket[i]<0) {
        				q = infopacket[i] + 256;
        			}
        			else {
        				q = infopacket[i];
        			}
                    pref_cat_1 = Integer.toBinaryString(q);
                    if(pref_cat_1.length()<8) {
                            String tmp_str = "";
                            String zero_str = "0";
                            for(int ii=0; ii<(8-pref_cat_1.length()); ii++) {
                                    tmp_str = tmp_str + zero_str;
                            }
                            pref_cat_1 = tmp_str + pref_cat_1;
                    }
        		}
        		else if(i==18) {
        			int q;
        			if(infopacket[i]<0) {
        				q = infopacket[i] + 256;
        			}
        			else {
        				q = infopacket[i];
        			}
        			pref_cat_2 = Integer.toBinaryString(q);
        			if(pref_cat_2.length()<8) {
                        String tmp_str = "";
                        String zero_str = "0";
                        for(int ii=0; ii<(8-pref_cat_2.length()); ii++) {
                                tmp_str = tmp_str + zero_str;
                        }
                        pref_cat_2 = tmp_str + pref_cat_2;
                    }
            	}
        	}
        	result[0] = username;
        	result[1] = pref_cat_1 + pref_cat_2;
        	return result;
        }
        
        // Method used to create META PROPOSAL PACKET
        // TODO Check the correctness of this method
        private byte[] createMetaProposalPacket(){
        	byte[] metaProposalPacket = new byte[META_PROP_PACKET_LENGTH];
        	int version = EpicVersionSettings.commVersion;
        	int type = EpicVersionSettings.metaPropType * 16;
        	metaProposalPacket[0] = (byte) (version + type);
        	
        	//META PROPOSAL PACKET: this field should be used for future development: 7 bit LENGTH + 1 bit EXTRA LENGTH
        	metaProposalPacket[1] = (byte) 0;
        	for(int i= 0; i<8; i++){
				try{					
					tmpEMId[i] = (EpicMsgIdPriority) contentStack.pop();
					String mac_first_part = tmpEMId[i].msg_id.substring(0,2);
					String mac_second_part = tmpEMId[i].msg_id.substring(2,4);
					metaProposalPacket[i*6+2] = toHex(mac_first_part);
					metaProposalPacket[i*6+3] = toHex(mac_second_part);
					byte[] time_tag_bytes = intToByteArray(Integer.parseInt(tmpEMId[i].msg_id.substring(4)));
					metaProposalPacket[i*6+4] = time_tag_bytes[0];
					metaProposalPacket[i*6+5] = time_tag_bytes[1];
					metaProposalPacket[i*6+6] = time_tag_bytes[2];
					metaProposalPacket[i*6+7] = time_tag_bytes[3];
					if(i == 7){
						if(!contentStack.empty()){
							metaProposalPacket[50] = (byte) 1;
						}else{
							metaProposalPacket[50] = (byte) 0;
						}
					}
				}
				catch(EmptyStackException e){
					metaProposalPacket[i*6+2] = (byte) 0;
					metaProposalPacket[i*6+3] = (byte) 0;
					metaProposalPacket[i*6+4] = (byte) 0;
					metaProposalPacket[i*6+5] = (byte) 0;
					metaProposalPacket[i*6+6] = (byte) 0;
					metaProposalPacket[i*6+7] = (byte) 0;
					if(i==7){
						metaProposalPacket[50] = (byte) 0;
					}
				}
			}
        	return metaProposalPacket;
        }
        
        // Method used to create METADATA ECHO PACKET
        // TODO Check the correctness of this method
        private Object[] createMetaEchoPacket(byte[] meta_proposal_bufferRX) {
            dbHelper.open();
            int acceptedContents = 0;
            int offset = 1;
            byte[] meta_echo_bufferTX = new byte[META_ECHO_PACKET_LENGTH];
            String msg_id;
            int reserved = 0;
            int msg_id_offset = 6;
            int version = EpicVersionSettings.commVersion;
            int type = EpicVersionSettings.metaEchoType * 16;                 
            meta_echo_bufferTX[0] = (byte) (version + type);
            
            for(int i = 0; i<8;i++){
                String b_mac1 = byteToString(meta_proposal_bufferRX[offset+1+msg_id_offset*i]);
                String b_mac2 = byteToString(meta_proposal_bufferRX[offset+2+msg_id_offset*i]);
                byte[] time_tag_arr = {meta_proposal_bufferRX[offset+3+msg_id_offset*i],
                		meta_proposal_bufferRX[offset+4+msg_id_offset*i],
                		meta_proposal_bufferRX[offset+5+msg_id_offset*i],
                		meta_proposal_bufferRX[offset+6+msg_id_offset*i]};
                
                int time_tag = byteArrayToInt(time_tag_arr);
                msg_id = b_mac1 + b_mac2 + time_tag;
                    
                if(!msg_id.equals("00000")) {
                    Cursor cursor = dbHelper.getContent(msg_id);
                    if(cursor.getCount() <= 0) {
                        reserved = reserved + 1* (int)Math.pow(2, (8-i-1));
                        acceptedContents++;
                    }
                    else {
                        reserved = reserved + 0* (int)Math.pow(2, (8-i-1));
                    }
                }
                else {
                    int fff = 10;
                }
            }
            // length field not yet used
            meta_echo_bufferTX[1] = (byte) 0;
            meta_echo_bufferTX[2] = (byte) reserved;
            dbHelper.close();
            Object[] result = {meta_echo_bufferTX,""+acceptedContents};
            return result;
        }
        
        // Method used to create CONTENT PACKET
        // TODO Check the correctness of this method
        private byte[] createContentPacket(String msgId) {
        	dbHelper.open();
			byte[] b = dbHelper.getContentByte(msgId, getApplicationContext());
			dbHelper.close();
			return b;
		}
        
        // Method used to retrieve the fixed part CONTENT PACKET
        // TODO Check the correctness of this method
        private Object[] getContentFixedPart(byte[] bfixed) {
        	// msg id
        	String msgId;
        	String b_mac1 = byteToString(bfixed[1]);
            String b_mac2 = byteToString(bfixed[2]);
            byte[] time_tag_array = {bfixed[3], bfixed[4], bfixed[5], bfixed[6]};            
            int time_tag = byteArrayToInt(time_tag_array);
            msgId = b_mac1 + b_mac2 + time_tag;
            
            // msg expire time
            long msgExpTime;
            byte[] time_exp_array = {bfixed[7],bfixed[8],bfixed[9],bfixed[10]};          
            msgExpTime = byteArrayToInt(time_exp_array);
            
            // msg latitude
            double msgLat;
            byte[] lat_array = {bfixed[11],bfixed[12],bfixed[13],bfixed[14],bfixed[15],bfixed[16],bfixed[17],bfixed[18]};
            msgLat = byteArrayToDouble(lat_array);
            // msg longitude
            double msgLon;
            byte[] lon_array = {bfixed[19],bfixed[20],bfixed[21],bfixed[22],bfixed[23],bfixed[24],bfixed[25],bfixed[26]};
            msgLon = byteArrayToDouble(lon_array);
            // msg altitude
            double msgAlt;
            byte[] alt_array = {bfixed[27],bfixed[28],bfixed[29],bfixed[30],bfixed[31],bfixed[32],bfixed[33],bfixed[34]};
            msgAlt = byteArrayToDouble(alt_array);
            
            // msg geo span
            int msgGeoSpan = (((int)bfixed[35] & 0xFF) << 8) + (((int)bfixed[36] & 0xFF) << 0);
            
            // msg categories
            String msgCategories;
            String cat_1;
            String cat_2;
            cat_1 = Integer.toBinaryString(bfixed[37] & 0xFF);
            if(cat_1.length()<8) {
                String tmp_str = "";
                String zero_str = "0";
                for(int ii=0; ii<(8-cat_1.length()); ii++) {
                        tmp_str = tmp_str + zero_str;
                }
                cat_1 = tmp_str + cat_1;
            }
            cat_2 = Integer.toBinaryString(bfixed[38] & 0xFF);
            if(cat_2.length()<8) {
                String tmp_str = "";
                String zero_str = "0";
                for(int ii=0; ii<(8-cat_2.length()); ii++) {
                        tmp_str = tmp_str + zero_str;
                }
                cat_2 = tmp_str + cat_2;
            }
            msgCategories = cat_1 + cat_2;
            
            // msg creator id
			String msgCreatorId = "";
			char blank = ' ';
			for(int i=0; i<16; i++) {
				if((char)bfixed[39+i] != blank) {
					msgCreatorId = msgCreatorId + (char)bfixed[39+i];  
				}
			}
			
			// msg creator nickname
			String msgCreatorNick = "";
			for(int i=0; i<16; i++) {
				if((char)bfixed[55+i] != blank) {
					msgCreatorNick = msgCreatorNick + (char)bfixed[55+i];  
				}
			}
			
			// hop number
			int hopNumber = (((int)bfixed[71] & 0xFF) << 8) + (((int)bfixed[72] & 0xFF) << 0);
			
			// approximate msg size
			int approximateMsgSize;
            byte[] ams_array = {bfixed[73],bfixed[74],bfixed[75],bfixed[76]};          
            approximateMsgSize = byteArrayToInt(ams_array);
			
            // rx msg rate
            double rxRate;
            byte[] rxRate_array = {bfixed[77],bfixed[78],bfixed[79],bfixed[80],bfixed[81],bfixed[82],bfixed[83],bfixed[84]};
            rxRate = byteArrayToDouble(rxRate_array);
            
            // msg md5 crc
            long crcCheck;
            byte[] crc_array = {bfixed[85],bfixed[86],bfixed[87],bfixed[88],bfixed[89],bfixed[90],bfixed[91],bfixed[92]};
            crcCheck = byteArrayToLong(crc_array);
            
			// number of attachments
			int attachNumber = (int)(bfixed[93] & 0xFF);
			
			// title length
			int titleLength = (int)(bfixed[94] & 0xFF);
			
			// content length
			int contentLength = (((int)bfixed[95] & 0xFF) << 8) + (((int)bfixed[96] & 0xFF) << 0);
			
			Object[] result = {msgId, msgExpTime, 
					msgLat, msgLon, msgAlt, msgGeoSpan, 
					msgCategories, msgCreatorId, msgCreatorNick,
					hopNumber, 
					approximateMsgSize, rxRate, crcCheck,
					attachNumber, 
					titleLength, contentLength};
			
        	return result;
        }

        //#########################################################
        // Method used to translate mac_id[i] (msg_id = {mac_id[0],mac_id[1],time_tag}) from String to byte representation
        // TODO Check the correctness of the returned value
        public byte toHex(String arg) {
		    byte b = (byte) Integer.parseInt(arg, 16);
		    return b;
        }
        
        // Method used to translate mac_id[i] (msg_id = {mac_id[0],mac_id[1],time_tag}) from byte representation to String
        // TODO Check the correctness of the returned value
        public String byteToString(byte arg) {
        	int c = (int) (arg & 0xFF); 
	        String b =  Integer.toHexString(c);
	        if(b.length()<2){
	        	b= "0"+b;
	        }
	        b = b.toUpperCase();
			return b;
        }

        public byte[] intToByteArray(int value) {
	        return new byte[] {
	                (byte)(value >> 24),
	                (byte)(value >> 16),
	                (byte)(value >> 8),
	                (byte)value};
        }
        
        public  int byteArrayToInt(byte [] b) {
       		return ((b[0] & 0xff) << 24)
       				+ ((b[1] & 0xff) << 16)
       				+ ((b[2] & 0xff) << 8)
       				+ (b[3] & 0xff);
       	}
        
        public double byteArrayToDouble(byte[] b) {
        	long fromByteLong = (((long)b[0] & 0xFF) << 56) + 
    				(((long)b[1] & 0xFF) << 48) + 
    				(((long)b[2] & 0xFF) << 40) + 
    				(((long)b[3] & 0xFF) << 32) + 
    				(((long)b[4] & 0xFF) << 24) + 
    				(((long)b[5] & 0xFF) << 16) +
    				(((long)b[6] & 0xFF) << 8)  +
    				(((long)b[7] & 0xFF) << 0);
    		double value = Double.longBitsToDouble(fromByteLong);
    		return value;
    	}
        
        public long byteArrayToLong(byte[] b) {
        	long value = (((long)b[0] & 0xFF) << 56) + 
    				(((long)b[1] & 0xFF) << 48) + 
    				(((long)b[2] & 0xFF) << 40) + 
    				(((long)b[3] & 0xFF) << 32) + 
    				(((long)b[4] & 0xFF) << 24) + 
    				(((long)b[5] & 0xFF) << 16) +
    				(((long)b[6] & 0xFF) << 8)  +
    				(((long)b[7] & 0xFF) << 0);
    		return value;
    	}
	}
    
    //#########################################################
    /**
     * Start the ConnectedThread to begin the sending/receiving activity
     * @param socket  The BluetoothSocket on which the connection was made
     * @param device  The BluetoothDevice that has been connected
     */
    public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
        // Cancel the thread that completed the connection
        if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}

        // Cancel any thread currently running a connection
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

        // Cancel the accept thread because we only want to connect to one device
        if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}

        // Start the thread to manage the connection and perform transmissions
        mConnectedThread = new ConnectedThread(socket);
        mConnectedThread.run();
        
//        // Write the name of the connected device to the SQLite DB History Table and runtime table
//        DevicesHistory dh_db = new DevicesHistory();
//        dh_db.AddDevice(device.getAddress(), device.getName());
    }
    
    //#########################################################
	/**
     * Set the current state of the chat connection
     * @param state  An integer defining the current connection state
     */
    private synchronized void setState(int state) {
        if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
        mState = state;
    }
    
    //#########################################################
    public EpicDevice getSelectedNeighborDevice() {
    	
//    	EpicDevice[] tmpDiscoveredDevices = new EpicDevice[devicesCounter];
//    	for(int i = 0; i < devicesCounter; i++){
//    		tmpDiscoveredDevices[i] = discoveredDevices[i];
//    	}
//    	discoveredDevices = tmpDiscoveredDevices;
//    	if(devicesCounter <= 1){}
//    	else{
//    		Arrays.sort(this.discoveredDevices);
//    	}
//    	Log.d("IOEpicService, getSelectedNeighborDevice()", "Try connection with this device...");
//    	return this.discoveredDevices[0];
    	
    	//##########################################
    	// getSelectedNeighborDevice() METHOD BODY #
    	//##########################################
    	int RSSI_OFFSET = 5;
    	EpicDevice result = null;
    	
		double[] intervals = new double[devicesCounter+1];
		double[] priority = new double[devicesCounter];
		EpicDevice[] tmpDiscoveredDevices = new EpicDevice[devicesCounter];
		
		for(int i=0; i<devicesCounter; i++) {
			tmpDiscoveredDevices[i] = discoveredDevices[i];
		}
		discoveredDevices = new EpicDevice[devicesCounter];
		for(int i=0; i<devicesCounter; i++) {
			discoveredDevices[i] = tmpDiscoveredDevices[i];
		}
		
		if(devicesCounter <= 1){
			result = discoveredDevices[0];
		}
		else {
			Arrays.sort(discoveredDevices);
			long rssiL = discoveredDevices[devicesCounter-1].getRssi();
			long rssiH = discoveredDevices[0].getRssi();
			double pTot = 0;
			
			for(int i=0; i<devicesCounter; i++) {
//				priority[i] = (discoveredDevices[i].getRssi() - rssiL + RSSI_OFFSET)*(discoveredDevices[i].getLastContact());
				priority[i] = (discoveredDevices[i].getRssi() - rssiL + RSSI_OFFSET);
				pTot = pTot + priority[i];
			}
			
			intervals[0] = 0;
			double s = 0;
			for(int i=0; i<devicesCounter; i++) {
				s = s + priority[i]/pTot;
				intervals[i+1] = s;
			}
			
			double randomChoice = Math.random();
			for(int i=0; i<devicesCounter; i++) {
				if(randomChoice>intervals[i] && randomChoice<intervals[i+1]) {
					result = discoveredDevices[i];
					if(i==0) {
						// ready for cleanSelectDevice() if necessary
					}
					else {
						// prepare for cleanSelectDevice() if necessary
						EpicDevice deviceTmp = new EpicDevice();
						deviceTmp = discoveredDevices[i];
						discoveredDevices[i] = discoveredDevices[0];
						discoveredDevices[0] = deviceTmp;
					}
					break;
				}
			}
		}
		Log.d("IOEpicService, getSelectedNeighborDevice()", "Try connection with this device...");
		
		return result;
		//##########################################
    	//##########################################
    	
    }
    
    public void cleanSelectedDevice(){
    	Log.d("IOEpicService, getSelectedNeighborDevice()", "...it is not an Epic device: connection failed");
    	devicesCounter--;
    	if(devicesCounter == 0){
    		Log.d("IOEpicService, getSelectedNeighborDevice()", "devicesCounter reached 0");
    		startListeningTimer();
    	}
    	else {
    		EpicDevice[] tmp = new EpicDevice[devicesCounter];
	  	   	for(int i=0; i<devicesCounter; i++){
	  		   tmp[i] = discoveredDevices[i+1];
	  	   	}
//	  	   	discoveredDevices = null;
//	  	   	discoveredDevices = new EpicDevice[devicesCounter];
	  	   	discoveredDevices = tmp;
	  	   	EpicDevice selectedDevice = getSelectedNeighborDevice();
	  	   	if(mConnectThread != null){
	  	   		mConnectThread = null;
	  	   	}
	  	   	mConnectThread = new ConnectThread(selectedDevice);
	   		mConnectThread.run();
    	}
     }
    
    //#########################################################
	/**
    * The IObindService interface to the service implementation
    */
	private final IIOEpicService.Stub mSecondaryBinder = new IIOEpicService.Stub() {
        // TODO Check the correctness of the following methods (do we need them?)
		
		public void sendContent() {
            //refresh sender content
        }
        
        public void receiveContent() {
        	//stay in listening mode
        	if(mBTAdapter.isDiscovering()) {
        		mBTAdapter.cancelDiscovery();
        		try {
//					mBTAdapter.listenUsingInsecureRfcommWithServiceRecord(getPackageName(), EPIC_UUID);
						mBTAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, EPIC_UUID);
				} catch (IOException e) {
					e.printStackTrace();
				}
        	}
        }	
	};
    
    //########################################
    //##      SERVICE CONNECTIONS           ##
    //########################################
    ServiceConnection mLocServiceConnection = new ServiceConnection() {
    	
    	public void onServiceConnected(ComponentName component, IBinder service) {
    		mILocationEpicService = ILocationEpicService.Stub.asInterface(service);
    	}
    	
    	public void onServiceDisconnected(ComponentName component) {
    		mLocBound = false;
    	}
    	
    };
    
	//#########################################################
	// TASK CLASSES
	//#########################################################
	private class DiscoveryTask extends TimerTask {
//		final Handler handlerScan = new Handler();
//		@Override
//		public void run() {
//        	handlerScan.post(new Runnable() {
                public void run() {
                	Log.d("DiscoveryTask, run()", "listeningTimer expired: run DiscoveryTask");
                	
                	if(mAcceptThread != null) {
                		mAcceptThread.cancel();
                		mAcceptThread = null;
                	}
                	if(mConnectThread != null) {
                		mConnectThread.cancel();
                		mConnectThread = null;
                	}
                    // every time startDiscovery() is going to be called devicesCounter should be set to 0
                    devicesCounter = 0;
                    if(discoveredDevices != null) {
                    	discoveredDevices = null;
                    }
                    discoveredDevices = new EpicDevice[MAX_NUMBER_OF_DESCOVERED_DEVICES];
                    
                    Log.d("DiscoveryTask, run()", "Set mState = STATE_DISCOVERY");
                    setState(STATE_DISCOVERING);
                    //Start Bluetooth Device Discovery
                    boolean isDiscoveryStarted = mBTAdapter.startDiscovery();
                    Log.d("DiscoveryTask, run()", "mBTAdapter.startDiscovery() = " + isDiscoveryStarted);
                    discoveryTimer.schedule(new CommunicationTask(), DISCOVERY_PERIOD);
                }
//           });
//        }
	}
	
	private class CommunicationTask extends TimerTask {
//		final Handler handlerSend = new Handler();
//        public void run() {
//            handlerSend.post(new Runnable() {
                public void run() {
                	Log.d("CommunicationTask, run()", "discoveryTimer expired: run CommunicationTask");
                	setState(STATE_POST_DISCOVERING);
                	
                	// stop Bluetooth Device Discovery
                	// cancelDiscovery() not useful because already performed in ConnectThread!!!
                	Log.d("DiscoveryTask, run()", "mBTAdapter.cancelDiscovery()");
		            mBTAdapter.cancelDiscovery();
		            
//		            TEST_PERIOD = LISTENING_PERIOD;
		            
		            if(devicesCounter>0) {
		            	Log.d("CommunicationTask, run()", "Try to connect with a bluetooth device");
		            	
		                //Send contents to new devices		                		                
	                	EpicDevice selectedDevice = getSelectedNeighborDevice();
	                	if(mConnectThread != null) {
	                		mConnectThread.cancel();
	                		mConnectThread = null;
	                	}
	                	mConnectThread = new ConnectThread(selectedDevice);
	                	mConnectThread.run();
		            }
		            else {
		            	Log.d("CommunicationTask, run()", "Bluetooth devices not found");
		            	startListeningTimer();
		            }
                }
//            });
//        }
    }
	
	private class CommunicationTimerElapsedTask extends TimerTask {
//		final Handler handler = new Handler();
//        public void run() {
//            handler.post(new Runnable() {
                public void run() {
                	if(mState == STATE_COMMUNICATION) {
	                	// communicationTimer elapsed: we assumed connection is lost
	                	Log.d("communicationTimerElapsedTask", "communicationTimer elapsed: connection is lost");
	                	if(mConnectedThread != null) {
	                		mConnectedThread.cancel();
	                		mConnectedThread = null;
	                	}
	                	startListeningTimer();
                	}
                }
//            });
//        }
    }
	
}
